<!--
 * @Author: fanyoubang
 * @Date: 2021-03-09 09:37:41
 * @LastEditTime: 2021-04-15 09:16:51
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \newxine:\xj-house\src\xjwDesign\xjw-calendar\index.vue
-->
<template>
  <view class="xjw-calendar">
    <view class="calendar-header">
      <view class="calendar-change_icon" @click="prevMonth">
        <view class="iconfont xjw-weixin_fanhuishangye"></view>
      </view>
      <view class="calendar-tiem">
        <view class="calendar_month">{{ month }}月</view>
        <view class="calendar_year">{{ year }}年</view>
      </view>
      <view class="calendar-change_icon" @click="afterMonth">
        <view class="iconfont xjw-weixin_fanhuishangye rotate"></view>
      </view>
    </view>
    <view class="calendar-content">
      <view class="calendar-week">
        <view
          class="calendar-week_item"
          v-for="(item, index) in week"
          :key="index"
          >{{ item }}</view
        >
      </view>
      <view class="calendar-day">
        <!-- 填充上个月 -->
        <view
          class="calendar-day-item"
          v-for="(item, index) in beforeMonthList"
          :key="index"
        >
          <block v-if="showBefore">
            <text class="">{{ item }}</text>
          </block>
        </view>
        <!-- 填充当前月 -->
        <view
          class="calendar-day-item"
          v-for="(item, index) in currentMonthList"
          :class="[item.class]"
          :key="index"
          @click="checkTime(item)"
        >
          <text
            :class="[
              {
                'calendar-day-item--active': checkResultTime.includes(item.time)
              }
            ]"
            >{{ item.day }}</text
          >
        </view>
        <!-- 填充下个月 -->
        <view
          class="calendar-day-item"
          v-for="(item, index) in afterMonthList"
          :key="index"
        >
          <block v-if="showAfter">
            <text class="">{{ item }}</text>
          </block>
        </view>
      </view>
    </view>
  </view>
</template>
<script lang="ts">
import Vue, { PropType } from "vue";
import { Component, Prop } from "vue-property-decorator";
import { format } from "@/xjwDesign/lib/utils/utils";
interface dayItem {
  day: number;
  time: string;
  disabled: boolean;
  class?: Array<string>;
}
type choiceType = "single" | "multiple" | "interval";
//保存当前日期实例
const nowData = new Date();

const readDate = new Date();
/**
 * @description: 获取当前月多少天
 * @param {*} year
 * @param {*} month
 * @return {*}
 */
function getDate(year, month) {
  return new Date(year, month, 0).getDate();
}
/**
 * @example: 比较时间大小
 */
function compareTime(after: string, before: string, bool: boolean) {
  if (!bool) {
    return Date.parse(after) > Date.parse(before) - 86400000;
  }
  return Date.parse(after) < Date.parse(before);
}
@Component
export default class Index extends Vue {
  @Prop({ type: [String, Array] }) value;
  // 选择类型
  @Prop({ type: String as PropType<choiceType>, default: "single" }) choice;
  // 是否能为空
  @Prop({ type: Boolean, default: false }) isEmpty;
  // 是否显示上月的日期
  @Prop({ type: Boolean, default: false }) showBefore;
  // 是否显示下个月的日期
  @Prop({ type: Boolean, default: false }) showAfter;
  // 是否可选全部日期
  @Prop({ type: Boolean, default: false }) isAll;
  // 当前日期之前
  @Prop({ type: Boolean, default: true }) isBefore;
  week: Array<string> = ["日", "一", "二", "三", "四", "五", "六"];
  year: number = 0;
  month: number = 0;
  day: number = 0;
  beforeMonthList: Array<string> = [];
  currentMonthList: Array<any> = [];
  afterMonthList: Array<string> = [];
  checkResultTime: Array<string> = [];
  created() {
    this.getDate(nowData);
    this.watchWalk();
  }
  getDate(date) {
    this.year = date.getFullYear();
    this.month = date.getMonth() + 1;
    this.day = date.getDate();
    this.initDate();
    if (this.choice === "interval") {
      this.setIntervalItemClass();
    }
  }
  /**
   * @description: 初始化数据
   */
  initDate() {
    // 获得当前月份1号是星期几
    const firstDay: number = this.getWeekDay(this.year, this.month, 1);
    // 获取上个月有多少天
    const afterDay: number = getDate(this.year, this.month - 1);
    // 获取当前月有多少天
    const currentDay: number = getDate(this.year, this.month);
    // 获取当前月最后一天是星期几
    const nextDay: number = this.getWeekDay(this.year, this.month, currentDay);

    this.beforeMonthList = this.fill(afterDay - firstDay, afterDay);
    this.currentMonthList = this.fill(0, currentDay, true);
    this.afterMonthList = this.fill(0, 6 - nextDay);

    this.currentMonthList.forEach(item => {
      if (this.isAll) {
        item.class.push("calendar-day-item--highlight");
      } else {
        if (compareTime(item.time, readDate.toString(), this.isBefore)) {
          item.class.push("calendar-day-item--highlight");
        } else {
          item.disabled = true;
        }
      }
    });
  }
  /**
   * @description: 获取星期几
   * @param {*} year 年
   * @param {*} month 月
   * @param {*} day 日
   * @return {*}
   */
  getWeekDay(year: number, month: number, day: number) {
    return new Date(`${year}/${month}/${day}`).getDay();
  }
  /**
   * @example: 下一个月
   */

  afterMonth() {
    if (this.month + 1 <= 12) {
      nowData.setMonth(this.month);
    } else {
      nowData.setFullYear(nowData.getFullYear() + 1);
      nowData.setMonth(0);
    }
    this.getDate(nowData);
  }
  /**
   * @example: 上一个月
   */
  prevMonth() {
    if (this.month - 1 > 0) {
      nowData.setMonth(this.month - 2);
    } else {
      nowData.setFullYear(nowData.getFullYear() - 1);
      nowData.setMonth(11);
    }
    this.getDate(nowData);
  }
  /**
   * @description: 填充日期
   * @param {*} star
   * @param {*} end
   * @param {*} current 是否当前月份
   * @return {*}
   */
  fill(star: number, end: number, current?: boolean) {
    const year = this.year;
    const month = this.month;
    const list: Array<any> = [];
    if (current) {
      for (let i = star + 1; i <= end; i++) {
        const boj: dayItem = {
          day: i,
          time: format(`${year}/${month}/${i}`, "yyyy/MM/dd"),
          disabled: false,
          class: []
        };
        list.push(boj);
      }
    } else {
      for (let i = star + 1; i <= end; i++) {
        list.push(i);
      }
    }
    return list;
  }

  watchWalk() {
    if (this.value) {
      if (Array.isArray(this.value)) {
        this.value.forEach(item => {
          this.checkResultTime.push(format(item, "yyyy/MM/dd"));
        });
        if (this.choice === "interval") {
          this.setIntervalItemClass();
        }
      } else {
        this.checkResultTime = [format(this.value, "yyyy/MM/dd")];
      }
    } else {
      this.checkResultTime = [format(readDate, "yyyy/MM/dd")];
    }
  }

  checkTime(item: dayItem) {
    if (item.disabled) {
      return;
    }
    switch (this.choice) {
      // 单选
      case "single":
        this.singleSelect(item);
        break;
      case "multiple":
        this.multipleSelect(item);
        break;
      case "interval":
        this.intervalSelect(item);
        return;
    }
  }
  /**
   * @description: 单选
   * @param {*} item
   * @return {*}
   */
  singleSelect(item: dayItem) {
    if (this.isEmpty) {
      this.checkResultTime.includes(item.time)
        ? (this.checkResultTime = [])
        : (this.checkResultTime = [item.time]);
    } else {
      this.checkResultTime = [item.time];
      // if (!this.checkResultTime.includes(item.time)) {
      //   this.checkResultTime = [item.time];
      // } else {
      //   return;
      // }
    }
    this.$emit("change", this.checkResultTime.join(""));
  }
  /**
   * @description: 多选
   * @param {*} item
   * @return {*}
   */
  multipleSelect(item: dayItem) {
    if (this.checkResultTime.includes(item.time)) {
      const filterList: Array<string> = this.checkResultTime.filter(
        v => v !== item.time
      );

      if (filterList.length === 0 && !this.isEmpty) {
        this.checkResultTime = [item.time];
      } else {
        this.checkResultTime = filterList;
      }
    } else {
      this.checkResultTime.push(item.time);
    }
    this.$emit("change", this.checkResultTime);
  }
  /**
   * @description: 区间
   * @param {*} item
   * @return {*}
   */
  intervalSelect(item: dayItem) {
    if (!Array.isArray(this.checkResultTime)) {
      this.checkResultTime = [];
    }
    if (this.checkResultTime.length === 2) {
      this.checkResultTime = [item.time];
    } else if (this.checkResultTime.length < 2) {
      if (this.checkResultTime.includes(item.time) && this.isEmpty) {
        this.checkResultTime = [];
      } else {
        if (compareTime(item.time, this.checkResultTime[0], true)) {
          this.checkResultTime.unshift(item.time);
        } else {
          this.checkResultTime.push(item.time);
        }
      }
    }
    this.setIntervalItemClass();

    if (this.checkResultTime.length === 2) {
      this.$emit("change", this.checkResultTime);
    }
  }
  /**
   * @description: 设置区间样式
   */
  setIntervalItemClass() {
    const className: string = "calendar-day-item--is-interval";
    this.currentMonthList.forEach(item => {
      // 设置区间样式
      if (
        compareTime(item.time, this.checkResultTime[0], false) &&
        compareTime(item.time, this.checkResultTime[1], true)
      ) {
        if (item.class.length > 0) {
          item.class.push(className);
        } else {
          item.class = [className];
        }
      } else {
        if (item.class.length > 0) {
          item.class = item.class.filter(v => v !== className);
        }
      }
      if (this.checkResultTime.length === 2) {
        if (item.time === this.checkResultTime[0]) {
          if (item.class.length > 0) {
            item.class.push("calendar-day-item--star-interval");
          } else {
            item.class = ["calendar-day-item--star-interval"];
          }
        } else {
          if (item.class.length > 0) {
            item.class = item.class.filter(
              v => v !== "calendar-day-item--star-interval"
            );
          }
        }
        if (item.time === this.checkResultTime[1]) {
          if (item.class.length > 0) {
            item.class.push("calendar-day-item--end-interval");
          } else {
            item.class = ["calendar-day-item--end-interval"];
          }
        } else {
          if (item.class.length > 0) {
            item.class = item.class.filter(
              v => v !== "calendar-day-item--end-interval"
            );
          }
        }
      } else {
        if (item.class.length > 0) {
          item.class = item.class.filter(
            v => v !== "calendar-day-item--star-interval"
          );
          item.class = item.class.filter(
            v => v !== "calendar-day-item--end-interval"
          );
        }
      }
    });
  }
}
</script>
<style lang="scss" scoped>
@import "@/styles/mixins.scss";
.xjw-calendar {
  line-height: 1;
  .calendar-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    .calendar-change_icon {
      background: #ffffff;
      padding: 0;
      width: 52upx;
      height: 52upx;
      line-height: 52upx;
      text-align: center;
      border-radius: 50%;
      box-shadow: 0px 10upx 44upx 0px rgba(0, 0, 0, 0.08);
      .xjw-weixin_fanhuishangye {
        font-size: 24upx;
        color: $f303133;
      }
    }
    .calendar-tiem {
      text-align: center;
      .calendar_month {
        font-size: 36upx;
        font-weight: bold;
        color: $f303133;
        margin-block: 12upx;
      }
      .calendar_year {
        font-size: 28upx;
        color: $f606266;
      }
    }
  }
  .calendar-content {
    width: 644upx;
    margin: 0 auto;
    .calendar-week {
      display: flex;
      flex-wrap: wrap;
      .calendar-week_item {
        height: 92upx;
        width: 92upx;
        color: $f909399;
        font-size: 32upx;
        text-align: center;
        line-height: 92upx;
      }
    }
    .calendar-day {
      display: flex;
      flex-wrap: wrap;
      .calendar-day-item {
        height: 92upx;
        width: 92upx;
        text-align: center;
        line-height: 92upx;
        flex-shrink: 0;
        color: $f909399;
        &--highlight {
          color: $f303133;
        }
        &--active {
          display: inline-block;
          width: 84upx;
          height: 84upx;
          line-height: 84upx;
          background: $base-color;
          color: #fff;
          font-weight: bold;
          border-radius: 50%;
        }
        &--is-interval {
          background: lighten($base-color, 30%);
        }
        &--star-interval {
          border-radius: 50% 0 0 50%;
          background: lighten($base-color, 30%);
        }
        &--end-interval {
          border-radius: 0 50% 50% 0;
          background: lighten($base-color, 30%);
        }
      }
    }
  }
}
.rotate {
  transform: rotate(180deg);
}
</style>
